package cn.cdjsyun.trms;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URL;
import java.time.Duration;
import java.util.*;
import java.util.NoSuchElementException;

public class Main {
  public static void main(String[] args) {
    // 设置 ChromeDriver 路径
    System.setProperty("webdriver.chrome.driver", "D:\\Project\\web-crawler\\chrome-windows\\chromedriver.exe");

    // 配置 Chrome 浏览器
    ChromeOptions options = new ChromeOptions();
    // 如果不想显示浏览器界面
    options.addArguments("--headless");
    // 设置启动时最大化浏览器窗口
    options.addArguments("--start-maximized");
    // 指定浏览器位置
    options.setBinary("D:\\Project\\web-crawler\\chrome-windows\\chrome.exe");
    WebDriver driver = new ChromeDriver(options);

    try {
      // 打开目标网站 替换为实际的网址
      driver.get("https://xxxxx/#/login?redirect_uri=https%3A%2F%2Fetax.sichuan.chinatax.gov.cn%2Fmhzx%2Fapi%2Fmh%2Ftpass%2Fcode&client_id=dddkead26f29477b9ea237d6845b8f44&response_type=code&state=c62b875ce3234de6a00daa1915b491c7&client_pid=dddkead26f29477b9ea237d6845b8f44");

      // 显式等待，确保页面加载完成
//      WebElement loginBtn = driver.findElement(By.className("loginBtnText"));
//      WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
//      WebElement loginButton = wait.until(ExpectedConditions.presenceOfNestedElementLocatedBy(By.className("loginBtnText")));
//      loginButton.click();

      // 显式等待，确保登录页面加载完成
      WebDriverWait loginWait = new WebDriverWait(driver, Duration.ofSeconds(30));

      // 根据实际的 img id 查找二维码图像
      WebElement qrcodeDiv = loginWait.until(ExpectedConditions.presenceOfElementLocated(By.id("qrcodeDiv")));
      List<WebElement> qrCodeImg = qrcodeDiv.findElements(By.tagName("img"));

      // 模拟滑动解锁（假设我们知道滑动的目标位置）
//      WebElement slider = driver.findElement(By.className("drag_text"));
//      Actions actions = new Actions(driver);
//      actions.clickAndHold(slider).moveByOffset(200, 0).release().perform();

//      // 等待登录后页面的加载
//      wait.until(ExpectedConditions.urlContains("loggedIn"));
//
//      System.out.println("登录成功!");

      // 获取 Cookies
      Set<Cookie> cookies = driver.manage().getCookies();
      Map<String, String> cookiesMap = new HashMap<>();
      for (Cookie cookie : cookies) {
        cookiesMap.put(cookie.getName(), cookie.getValue());
        System.out.println("Cookie: " + cookie.getName() + " = " + cookie.getValue());
      }

      // 假设 Token 存储在 localStorage 或 cookie 中
      Cookie tokenCookie = driver.manage().getCookieNamed("token");
      String token = null;
      if (tokenCookie != null) {
        token = tokenCookie.getValue();
        System.out.println("Token: " + token);
      }

//      // 在这里我们假设我们需要从 Cookie 或 localStorage 获取其他信息
//      // 获取 localStorage 数据
//      JavascriptExecutor js = (JavascriptExecutor) driver;
//      String localStorageDatas = (String) js.executeScript("return window.localStorage;");
//      System.out.println("localStorageDatas: " + localStorageDatas);
//      String localStorageData = (String) js.executeScript("return window.localStorage.getItem('yourStorageKey');");
//      System.out.println("LocalStorage: " + localStorageData);
//
//      // 获取 sessionStorage 数据
//      String sessionStorageData = (String) js.executeScript("return window.sessionStorage.getItem('yourStorageKey');");
//      System.out.println("SessionStorage: " + sessionStorageData);


      // 获取二维码图片的 src URL
      String qrCodeSrc = qrCodeImg.get(0).getAttribute("src");

      // 处理二维码（Base64 或 URL）
      BufferedImage qrImage = null;
      // 如果二维码图片的 src 是 Base64 编码的，直接转换
      if (qrCodeSrc.startsWith("data:image/png;base64,")) {
        String base64Data = qrCodeSrc.substring("data:image/png;base64,".length());
        byte[] imageBytes = Base64.getDecoder().decode(base64Data);
        qrImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
//        printQRCodeToConsole(qrImage);
      } else {
        // 如果二维码图片是通过 URL 提供的，下载该图片
        qrImage = ImageIO.read(new URL(qrCodeSrc));
//        printQRCodeToConsole(qrImage);
      }
      // 设定图片路径和格式
      File outputfile = new File("D:\\Project\\web-crawler\\qrcode\\output_image.png");

      // 保存图片为 PNG 格式
      ImageIO.write(qrImage, "PNG", outputfile);
      waitQRcodeLogin(qrImage, driver);
    } catch (Exception e) {
      System.out.println("An error occurred: " + e.getMessage());
      e.printStackTrace();
    } finally {
      driver.quit();
    }
  }

  private static void waitQRcodeLogin(BufferedImage qrImage, WebDriver driver) throws Exception {
    // 使用 ZXing 库解析二维码中的内容
    String qrCodeContent = decodeQRCode(qrImage);
    System.out.println("QR Code Content: " + qrCodeContent);

    // 等待用户扫码并登录，定期检查是否登录成功
    boolean isLoggedIn = false;
    int attempts = 0;
    // 最多等待 60 次（大约 5 分钟）
    while (!isLoggedIn && attempts < 60) {
      try {
        // 替换为你实际检查登录状态的逻辑 替换为登录成功后的页面元素
        List<WebElement> loggedInElement = driver.findElements(By.className("leftTopItem"));
        loggedInElement.forEach(element -> {
              if (element.isDisplayed()) {
                readyCookieAndCache(driver);
                System.out.println("element: " + element.findElement(By.tagName("span")).getText());
              }
            }
        );
//        if (loggedInElement.isDisplayed()) {
//          System.out.println("登录成功！");
//          isLoggedIn = true;
//        }
      } catch (NoSuchElementException e) {
        // 页面中没有登录成功的元素，继续轮询
      }

      if (!isLoggedIn) {
        // 每 5 秒轮询一次
        Thread.sleep(5000);
        attempts++;
      }
    }

    if (!isLoggedIn) {
      System.out.println("未能在规定时间内完成扫码登录");
    }
  }

  private static void readyCookieAndCache(WebDriver driver) {
    // 读取 localStorage
    JavascriptExecutor js = (JavascriptExecutor) driver;
    Map<String, Object> localStorage = (Map<String, Object>) js.executeScript(
        "var storage = {}; " +
            "for (var i = 0; i < localStorage.length; i++) { " +
            "    var key = localStorage.key(i); " +
            "    storage[key] = localStorage.getItem(key); " +
            "} return storage;");

    System.out.println("localStorage: " + localStorage);

    // 读取 sessionStorage
    Map<String, Object> sessionStorage = (Map<String, Object>) js.executeScript(
        "var storage = {}; " +
            "for (var i = 0; i < sessionStorage.length; i++) { " +
            "    var key = sessionStorage.key(i); " +
            "    storage[key] = sessionStorage.getItem(key); " +
            "} return storage;");

    System.out.println("sessionStorage: " + sessionStorage);
  }

  // 使用 ZXing 解析二维码图片
  private static String decodeQRCode(BufferedImage qrImage) throws Exception {
    if (qrImage == null) {
      return null;
    }

    // 创建二维码解码器
    QRCodeReader reader = new QRCodeReader();
    LuminanceSource source = new BufferedImageLuminanceSource(qrImage);
    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

    // 解码二维码
    Result result = reader.decode(bitmap);
    return result.getText();
  }

  /**
   * 将二维码图片转换为 ASCII 图像并打印到控制台
   *
   * @param qrImage
   */
  private static void printQRCodeToConsole(BufferedImage qrImage) {
    int width = qrImage.getWidth();
    int height = qrImage.getHeight();
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        // 获取每个像素的 RGB 值
        int rgb = qrImage.getRGB(x, y);
        // 转为灰度
        int gray = (int) ((0.3 * ((rgb >> 16) & 0xFF)) + (0.59 * ((rgb >> 8) & 0xFF)) + (0.11 * (rgb & 0xFF)));

        // 根据灰度值选择字符
        // 灰度值小于 128 使用 '#'，否则使用空格
        char c = (gray < 128) ? '#' : ' ';
        System.out.print(c);
      }
      // 换行
      System.out.println();
    }
  }
}